﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Resources;
using System.Windows.Markup;

namespace ProtoXaml
{

    public class Skinning
    {
        public Skinning()
        {
            //foreach (FontFamily fontFamily in Fonts.GetFontFamilies(new Uri("pack://application:,,,/ProtoXaml;component/"), "./Skins/"))
            //{
            //    Console.WriteLine(fontFamily.FamilyNames[System.Windows.Markup.XmlLanguage.GetLanguage("en-US")]);
            //}

            _skins = new Dictionary<string, string>();
                                           
            this.RegisterSkin("Default", "pack://application:,,,/ProtoXaml;component/Skins/DefaultSkin.xaml");
            this.RegisterSkin("Napkin", "pack://application:,,,/ProtoXaml;component/Skins/NapkinSkin.xaml");
        }

        private Dictionary<string, string> _skins;

        public void RegisterSkin(string skinName, string path)
        {
            _skins.Add(skinName, path);
        }

        public IEnumerable<string> Skins
        {
            get { return _skins.Keys; }
        }

        public event CurrentSkinNameChangedEvent CurrentSkinNameChanged;

        
        private string _selectedSkinName;

        public string SelectedSkinName
        {
            get { return _selectedSkinName; }
            set
            {
                if (value != _selectedSkinName)
                {
                    _selectedSkinName = value;
                    SetCurrentSkin(_selectedSkinName);
                    if (CurrentSkinNameChanged != null)
                        CurrentSkinNameChanged(this, new CurrentSkinNameChangedEventArgs(_selectedSkinName));
                }
            }
        }



        private void SetCurrentSkin(string skin)
        {
            string path;
            if (_skins.TryGetValue(skin, out path))
            {
                Uri uri = new Uri(path, UriKind.Absolute);
                StreamResourceInfo info = Application.GetResourceStream(uri);
                ResourceDictionary rd = (ResourceDictionary)XamlReader.Load(info.Stream);

                Application.Current.Resources = rd;            
            }
            else
            {
                throw new Exception("no such skin");
            }
        }


        // ////////////////////////////////////////
        // the Command that is used for Menues and Shortcut keys

        public static RoutedUICommand SwitchToSkinCommand =
            new RoutedUICommand("Switch To Skin", "SwitchToSkin", typeof(Skinning));


        // ////////////////////////////////////////
        // Adding Skins to a menu and handling SkinChanged events to update the menu

        MenuItem _menu;

        public void AddSkinsToMenu(Window wnd, MenuItem menu)
        {
            _menu = menu;

            CommandBinding switchToSkinCommandBinding = new CommandBinding(Skinning.SwitchToSkinCommand);
            switchToSkinCommandBinding.Executed += new ExecutedRoutedEventHandler(switchToSkinCommandBinding_Executed);
            wnd.CommandBindings.Add(switchToSkinCommandBinding);
            
            foreach (string skin in this.Skins)
            {
                MenuItem mi = new MenuItem();
                mi.Header = skin;
                mi.Command = SwitchToSkinCommand;
                mi.CommandParameter = skin;

                menu.Items.Add(mi);
            }

            // change the menu status when the skin changes
            this.CurrentSkinNameChanged += new CurrentSkinNameChangedEvent(Skinning_CurrentSkinNameChanged);
        }

        private void switchToSkinCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            this.SelectedSkinName = (string)e.Parameter;
        }
        
        private void Skinning_CurrentSkinNameChanged(object sender, CurrentSkinNameChangedEventArgs eventArgs)
        {
            foreach (MenuItem mi in _menu.Items)
                mi.IsChecked = (eventArgs.SkinName.CompareTo(mi.Header) == 0);
        }

        // ////////////////////////////////////////
        // add Shortcut keys that bind to the SwithToSkin-Command

        public void RegisterKey(Window wnd, string skinName, Key key, ModifierKeys modifierKeys)
        {
            KeyBinding kb = new KeyBinding(Skinning.SwitchToSkinCommand, key, modifierKeys);
            kb.CommandParameter = skinName;
            wnd.InputBindings.Add(kb);
        }
    }


    public delegate void CurrentSkinNameChangedEvent(object sender, CurrentSkinNameChangedEventArgs eventArgs);

    public class CurrentSkinNameChangedEventArgs : EventArgs
    {
        public CurrentSkinNameChangedEventArgs(string skinName) { SkinName = skinName; }

        string _skinName;
        public string SkinName
        {
            get { return _skinName; }
            set { _skinName = value; }
        }
    }
}
